var aup = {
	util : {}
};

aup.byId = function(idSelector) {
	var domElem = document.getElementById(idSelector);
	if (domElem) {
		return new AupElement(domElem);
	} else {
		return undefined;
	}
}

aup.byTag = function(tagName) {
	var result = [];
	var domElems = document.getElementsByTagName(tagName);
	if (domElems) {
		for ( var dei = 0; dei < domElems.length; dei++) {
			result.push(aup.byElement(domElems[dei]));
		}

		return result;
	} else {
		return undefined;
	}
}

aup.byElement = function(element) {
	if (element == null) {
		return null;
	}
	return new AupElement(element);
}
function AupNode(node) {
	if(node){
		this.node = node;
		this.type = node.nodeType;
		if (!this.node.extraData) {
			this.node.extraData = {};
		}
	}
}
AupNode.prototype.data = function(name, value) {
	if (value !== undefined) {
		this.node.extraData[name] = value;
	} else {
		return this.node.extraData[name];
	}
}
AupNode.prototype.hasData = function(name) {
	var data = this.node.extraData[name];
	return data && data != null;
}
AupNode.prototype.removeData = function(name) {
	delete this.node.extraData[name];
}

function AupText(textNode, element) {
	AupNode.call(this, textNode);
	this.textNode = textNode;
	this.parentElement = element;
}

AupText.prototype = new AupNode();
AupText.prototype.constructor = AupText;

AupText.prototype.element = function(){
	return this.parentElement;
}
AupText.prototype.text = function(value){
	if(value !== undefined){this.textNode.nodeValue = value; return;}
	return this.textNode.nodeValue;
}


function AupElement(element) {
	AupNode.call(this, element);
	this.element = element;
}

AupElement.prototype = new AupNode();
AupElement.prototype.constructor = AupElement;


AupElement.prototype.node = function() {
	return new AupNode(this.element);
}

AupElement.prototype.on = function(event, subscribeFn) {
	if(subscribeFn === undefined){
		var events = this.element['events_subs'];
		if(!events) return undefined;
		return events[event];
	}
	
	var eventListener = function(evt){
		var eventReturn = subscribeFn();
		
		if (eventReturn == false) {
			if (evt.preventDefault) {
				evt.preventDefault();
			} else {
				evt.returnValue = false;
			}
		}
		
	}
	
	
	if (this.element.addEventListener) // W3C DOM
		this.element.addEventListener(event, eventListener, false);
	else if (this.element.attachEvent) { // IE DOM
		this.element.attachEvent("on" + event, eventListener);
	}
	
	var events = this.element['events_subs'];
	if (!events) {
		events = {};
		this.element['events_subs'] = events;
	}
	if(!events[event]) events[event] =[]; 
	events[event].push(subscribeFn);
}

AupElement.prototype.fire = function(event) {
	var e = null;
	if (document.createEventObject) {
		// IE DOM
		e = document.createEventObject();
		this.element.fireEvent('on' + event, e);
	} else {
		// W3C DOM
		e = document.createEvent('HTMLEvents');
		e.initEvent(event, true, true);
		this.element.dispatchEvent(e);
	}
}

AupElement.prototype.attr = function(name, value) {
	if (value) {
		this.element.setAttribute(name, value);
	} else {
		return this.element.getAttribute(name, 2);
	}
}

AupElement.prototype.removeAttr = function(name) {
	this.element.removeAttribute(name);
}

AupElement.prototype.style = function(name, value) {
	if (value == '' || value == null) {
		this.element.style[name] = '';
		return;
	}
	if (value) {
		this.element.style[name] = value;
	} else {
		return this.element.style[name];
	}
}


AupElement.prototype.hasClass = function(name) {
    return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(this.element.className);
};

AupElement.prototype.addClass = function(name) {
    this.element.className = this.element.className ? this.element.className += (" " + name) : name;
};

AupElement.prototype.removeClass = function(name) {
    var c = this.element.className;
    this.element.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), "");
};


AupElement.prototype.html = function(value) {
	if (value) {
		this.element.innerHTML = value;
	} else {
		return this.element.innerHTML;
	}
}
AupElement.prototype.text = function(value) {
	if (value || value == '0') {
		while (this.element.firstChild) {
			this.element.removeChild(this.element.firstChild);
		}
		var text = document.createTextNode(value);
		this.element.appendChild(text);

	} else {
		if (this.element.textContent)
			return this.element.textContent;
		return this.element.innerText;
	}
}
AupElement.prototype.fieldValue = function(newValue) {
	if(newValue === undefined){
		if(this.element.tagName === 'SELECT'){
			throw new Error('fieldValue not supported for ' + this.element.tagName);
		}
		if(this.element.tagName === 'INPUT'){
			return this.element.value; 
		}
		throw new Error('fieldValue not supported for ' + this.element.tagName);	
	} else {
		if(this.element.tagName === 'SELECT'){
			throw new Error('fieldValue not supported for ' + this.element.tagName);
		}
		if(this.element.tagName === 'INPUT'){
			this.element.value = newValue; return;
		}
		throw new Error('fieldValue not supported for ' + this.element.tagName);	
	}
	
}

AupElement.prototype.append = function(child) {
	this.element.appendChild(child.element);
}

AupElement.prototype.next = function(nextEl) {
	if (nextEl) {
		this.element.parentNode.insertBefore(nextEl.element,
				this.element.nextSibling);
	} else {
		return aup.util.newAupElement(this.element.nextSibling);
	}
}
AupElement.prototype.replace = function(newEl) {
	this.element.parentNode.replaceChild(newEl.element,this.element);

}
AupElement.prototype.before = function(beforeEl) {
	if (beforeEl) {
		this.element.parentNode.insertBefore(beforeEl.element, this.element);
	} else {
		return aup.util.newAupElement(this.element.previousSibling);
	}
}
AupElement.prototype.children = function() {
	var chld = this.element.children;
	var children = [];
	for ( var ci = 0; ci < chld.length; ci++) {
		children.push(new AupElement(chld[ci]));
	}
	return children;
}
AupElement.prototype.childNodes = function() {
	var chld = this.element.childNodes;
	var children = [];
	for ( var ci = 0; ci < chld.length; ci++) {
		var child = chld[ci];
		if(child.nodeType == 1) { children.push(new AupElement(child)); continue;}
		if(child.nodeType == 3) { children.push(new AupText(child, this)); continue;}
	}
	return children;
}

AupElement.prototype.parent = function() {
	return aup.util.newAupElement(this.element.parentNode);
}
AupElement.prototype.empty = function() {
	while (this.element.firstChild) {
		this.element.removeChild(this.element.firstChild);
	}
}

AupElement.prototype.clone = function(descriptor) {
	var events=true, data=true;
	var handler;
	if(descriptor && descriptor.events && descriptor.events == false) events = false;
	if(descriptor && descriptor.data && descriptor.data == false) data = false;
	if(descriptor && descriptor.handler) handler = descriptor.handler;
	
	var ae = new AupElement(this.element.cloneNode(true));

	// events
	aup.util.cloneDataAndEvents(this.element, ae.element, events, data, handler);
	return ae;
}

aup.util.cloneDataAndEvents = function(from, to, events, data, handler) {
	if(events == true){
		var events_subs = from['events_subs'];
		if (events_subs) {
			for ( var eventName in events_subs) {
				aup.byElement(to).on(eventName, events_subs[eventName]);
			}
		}
	}
	if(data == true){
		to.extraData = aup.util.cloneObj(from.extraData); 
		//if(to.extraData != [])alert(JSON.stringify(from.extraData));
		//if(to.extraData != [])alert(JSON.stringify(to.extraData));
	}
	
	if(handler) handler(aup.byElement(to));
	if(handler != undefined || data == true || events == true){ 
		for ( var ci = 0; ci < from.childNodes.length; ci++) {
			aup.util.cloneDataAndEvents(from.childNodes[ci], to.childNodes[ci], events, data, handler);
		}
	}
}
aup.util.cloneObj =  function(obj) {
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Array
    if (obj instanceof Array) {
    	var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = aup.util.cloneObj(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            copy[attr] = aup.util.cloneObj(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

AupElement.prototype.remove = function() {
	this.element.parentNode.removeChild(this.element);
}



// AJAX
aup.ajax = function(options) {
	var ids = [ 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' ];
	var xhr;

	if (typeof window.XMLHttpRequest === 'function') {
		xhr = new XMLHttpRequest();
	} else { // For IE versions below 7
		for ( var i = 0; i < ids.length; i++) {
			try {
				xhr = new ActiveXObject(ids[i]);
				break;
			} catch (e) {
			}
		}
	}

	var data = options.data;
	if (typeof data !== "string") {
		data = aup.util.JSONToUrl(data);
	}

	var httpMethod = options.type;
	if (!httpMethod) {
		httpMethod = 'GET';
	} else {
		httpMethod = httpMethod.toUpperCase();
	}

	var requestUrl = options.url;
	if (!requestUrl)
		throw new Error('Ajax with no URL');
	if (httpMethod === 'GET') {
		requestUrl = requestUrl + '?' + data;
	}

	var retType = options.retType;
	if (!retType) {
		retType = 'TEXT';
	} else {
		retType = retType.toUpperCase();
	}

	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {

			// SUCCESS
			if (xhr.status == 200) {
				var successFunc = options.success;
				if (successFunc) {
					var retObj;
					if (retType === 'XML') {
						var dp = new DOMParser();
						retObj = dp.parseFromString(xhr.responseText,
								"text/xml");
					}
					if (retType === 'JSON') {
						retObj = JSON.parse(xhr.responseText);
					}
					if (retType === 'TEXT') {
						retObj = xhr.responseText;
					}
					successFunc(retObj);
				}

			} else { // ERROR
				var errorFunc = options.error;
				errorcFunc(xhr.status);
			}
		}

	};
	xhr.open(httpMethod, requestUrl, true);
	if (httpMethod === 'GET') {
		xhr.send();
		return;
	}
	if (httpMethod === 'POST') {
		xhr.setRequestHeader("Content-type",
				"application/x-www-form-urlencoded");
		xhr.send(data);
		return;
	}

}
aup.util.newAupElement = function(obj) {
	if (obj == null)
		return null;
	if (obj instanceof AupElement)
		return obj;
	if (aup.util.isElement(obj))
		return new AupElement(obj);
	return undefined;
}

aup.util.isElement = function(o) {
	return (typeof HTMLElement === "object" ? o instanceof HTMLElement : // DOM2
	o && typeof o === "object" && o !== null && o.nodeType === 1
			&& typeof o.nodeName === "string");
}

aup.util.JSONToUrl = function(a1) {
	var u = [];
	for (x in a1) {
		if (a1[x] instanceof Array)
			u.push(x + "=" + encodeURI(a1[x].join(",")));
		else if (a1[x] instanceof Object)
			u.push(aup.util.JSONToUrl(a1[x]));
		else
			u.push(x + "=" + encodeURI(a1[x]));
	}
	return u.join("&amp;");
}

aup.util.isNumber = function(n) {
	return !isNaN(parseFloat(n)) && isFinite(n);
}

aup.util.isFunction = function(value) {
	return 'function' === typeof value;
}
aup.util.isArray = function(value) {
	if (Array.isArray) {
		return Array.isArray(value);
	} else {
		return typeof obj === "array";
	}

}
aup.util.isObject = function(value) {
	return value && value !== null && (typeof value == "object");
}


aup.util.trim = function(value) {
	return value.replace(/^\s+|\s+$/g, '');
}
aup.util.indexOf = function(ar, searchElement) {
	if (ar == null) {
		throw new TypeError();
	}
	var n, k, t = Object(ar), len = t.length >>> 0;

	if (len === 0) {
		return -1;
	}
	n = 0;
	if (arguments.length > 1) {
		n = Number(arguments[1]);
		if (n != n) { // shortcut for verifying if it's NaN
			n = 0;
		} else if (n != 0 && n != Infinity && n != -Infinity) {
			n = (n > 0 || -1) * Math.floor(Math.abs(n));
		}
	}
	if (n >= len) {
		return -1;
	}
	for (k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); k < len; k++) {
		if (k in t && t[k] === searchElement) {
			return k;
		}
	}
	return -1;
}